﻿// Decompiled with JetBrains decompiler
// Type: TaleWorlds.CampaignSystem.Settlements.Village
// Assembly: TaleWorlds.CampaignSystem, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: E85F8C15-4DF6-4E9C-A58A-29177E40D07A
// Assembly location: D:\steam\steamapps\common\Mount & Blade II Bannerlord\bin\Win64_Shipping_Client\TaleWorlds.CampaignSystem.dll

using System.Collections.Generic;
using System.Xml;
using TaleWorlds.CampaignSystem.Actions;
using TaleWorlds.CampaignSystem.MapEvents;
using TaleWorlds.CampaignSystem.Party;
using TaleWorlds.CampaignSystem.Party.PartyComponents;
using TaleWorlds.Core;
using TaleWorlds.Library;
using TaleWorlds.ObjectSystem;
using TaleWorlds.SaveSystem;

#nullable disable
namespace TaleWorlds.CampaignSystem.Settlements
{
  public class Village : SettlementComponent
  {
    public const int MidHearthThreshold = 600;
    public const int LowHearthThreshold = 200;
    private const int InitialVillageGold = 1000;
    public const int NumberOfDaysToFillVillageStocks = 5;
    [CachedData]
    public VillagerPartyComponent VillagerPartyComponent;
    [SaveableField(104)]
    private Village.VillageStates _villageState;
    [SaveableField(106)]
    private Settlement _bound;
    public VillageType VillageType;
    private Settlement _tradeBound;
    [SaveableField(107)]
    private VillageMarketData _marketData;

    internal static void AutoGeneratedStaticCollectObjectsVillage(
      object o,
      List<object> collectedObjects)
    {
      ((MBObjectBase) o).AutoGeneratedInstanceCollectObjects(collectedObjects);
    }

    protected override void AutoGeneratedInstanceCollectObjects(List<object> collectedObjects)
    {
      base.AutoGeneratedInstanceCollectObjects(collectedObjects);
      collectedObjects.Add((object) this._bound);
      collectedObjects.Add((object) this._marketData);
    }

    internal static object AutoGeneratedGetMemberValueLastDemandSatisfiedTime(object o)
    {
      return (object) ((Village) o).LastDemandSatisfiedTime;
    }

    internal static object AutoGeneratedGetMemberValueHearth(object o)
    {
      return (object) ((Village) o).Hearth;
    }

    internal static object AutoGeneratedGetMemberValueTradeTaxAccumulated(object o)
    {
      return (object) ((Village) o).TradeTaxAccumulated;
    }

    internal static object AutoGeneratedGetMemberValue_villageState(object o)
    {
      return (object) ((Village) o)._villageState;
    }

    internal static object AutoGeneratedGetMemberValue_bound(object o)
    {
      return (object) ((Village) o)._bound;
    }

    internal static object AutoGeneratedGetMemberValue_marketData(object o)
    {
      return (object) ((Village) o)._marketData;
    }

    public static MBReadOnlyList<Village> All => Campaign.Current.AllVillages;

    public IEnumerable<PartyBase> GetDefenderParties(MapEvent.BattleTypes battleType)
    {
      Village village = this;
      yield return village.Settlement.Party;
      foreach (MobileParty party in (List<MobileParty>) village.Settlement.Parties)
      {
        if (party.MapFaction == village.Settlement.MapFaction && (!party.IsMilitia && !party.IsVillager || battleType == MapEvent.BattleTypes.Raid || battleType == MapEvent.BattleTypes.IsForcingSupplies || battleType == MapEvent.BattleTypes.IsForcingVolunteers) && !party.IsCaravan)
          yield return party.Party;
      }
    }

    public PartyBase GetNextDefenderParty(ref int partyIndex, MapEvent.BattleTypes battleType)
    {
      ++partyIndex;
      if (partyIndex == 0)
        return this.Settlement.Party;
      for (int index = partyIndex - 1; index < this.Settlement.Parties.Count; ++index)
      {
        MobileParty party = this.Settlement.Parties[index];
        if (party.MapFaction == this.Settlement.MapFaction && !party.IsCaravan)
        {
          partyIndex = index + 1;
          return party.Party;
        }
      }
      return (PartyBase) null;
    }

    public Village.VillageStates VillageState
    {
      get => this._villageState;
      set
      {
        if (this._villageState == value)
          return;
        this._villageState = value;
        switch (this._villageState)
        {
          case Village.VillageStates.Normal:
            CampaignEventDispatcher.Instance.OnVillageBecomeNormal(this);
            break;
          case Village.VillageStates.BeingRaided:
            CampaignEventDispatcher.Instance.OnVillageBeingRaided(this);
            break;
          case Village.VillageStates.Looted:
            CampaignEventDispatcher.Instance.OnVillageLooted(this);
            break;
        }
      }
    }

    public bool IsDeserted => this._villageState == Village.VillageStates.Looted;

    [SaveableProperty(105)]
    public float LastDemandSatisfiedTime { get; private set; }

    public Settlement Bound
    {
      get => this._bound;
      private set
      {
        if (this._bound == value)
          return;
        this._bound?.RemoveBoundVillageInternal(this);
        this._bound = value;
        this._bound?.AddBoundVillageInternal(this);
      }
    }

    public Settlement TradeBound
    {
      get => !this._bound.IsTown ? this._tradeBound : this._bound;
      internal set
      {
        if (this._tradeBound == value || this._bound.IsTown)
          return;
        this._tradeBound?.Town.RemoveTradeBoundVillageInternal(this);
        this._tradeBound = value;
        this._tradeBound?.Town.SetTradeBoundVillageInternal(this);
      }
    }

    public VillageMarketData MarketData => this._marketData;

    [SaveableProperty(108)]
    public float Hearth { get; set; }

    [SaveableProperty(110)]
    public int TradeTaxAccumulated { get; set; }

    public Village()
    {
      this.LastDemandSatisfiedTime = -1f;
      this._marketData = new VillageMarketData(this);
    }

    public void DailyTick()
    {
      int hearthLevel1 = this.GetHearthLevel();
      this.Hearth += this.HearthChange;
      int hearthLevel2 = this.GetHearthLevel();
      if (hearthLevel1 != hearthLevel2)
        this.Settlement.Party.SetLevelMaskIsDirty();
      if ((double) this.Hearth < 10.0)
        this.Hearth = 10f;
      this.Owner.Settlement.Militia += this.MilitiaChange;
      if (this.Gold <= 1000)
        return;
      this.ChangeGold(1000 - this.Gold);
    }

    public override void OnInit()
    {
      ChangeVillageStateAction.ApplyBySettingToNormal(this.Settlement);
      this.ChangeGold(1000);
    }

    public int GetWerehouseCapacity()
    {
      float productionAmount1 = Campaign.Current.Models.VillageProductionCalculatorModel.CalculateDailyFoodProductionAmount(this);
      foreach ((ItemObject, float) production in (List<(ItemObject, float)>) this.VillageType.Productions)
      {
        float productionAmount2 = Campaign.Current.Models.VillageProductionCalculatorModel.CalculateDailyProductionAmount(this, production.Item1);
        productionAmount1 += productionAmount2;
      }
      return MathF.Ceiling(MathF.Max(1f, productionAmount1) * 5f);
    }

    public override int GetItemPrice(ItemObject item, MobileParty tradingParty = null, bool isSelling = false)
    {
      return this.TradeBound == null ? 1 : this.TradeBound.Town.MarketData.GetPrice(item, tradingParty, isSelling);
    }

    public override int GetItemPrice(
      EquipmentElement itemRosterElement,
      MobileParty tradingParty = null,
      bool isSelling = false)
    {
      return this.TradeBound == null ? 1 : this.TradeBound.Town.MarketData.GetPrice(itemRosterElement, tradingParty, isSelling);
    }

    public override string ToString() => this.Name.ToString();

    public override void Deserialize(MBObjectManager objectManager, XmlNode node)
    {
      int num = this.IsInitialized ? 1 : 0;
      base.Deserialize(objectManager, node);
      this.BackgroundCropPosition = float.Parse(node.Attributes["background_crop_position"].Value);
      this.BackgroundMeshName = node.Attributes["background_mesh"].Value;
      this.CastleBackgroundMeshName = node.Attributes["castle_background_mesh"].Value;
      this.WaitMeshName = node.Attributes["wait_mesh"].Value;
      if (num == 0)
        this.Hearth = (float) int.Parse(node.Attributes["hearth"].Value);
      this.VillageType = (VillageType) objectManager.ReadObjectReferenceFromXml("village_type", typeof (VillageType), node);
      if (num != 0)
        return;
      this.Bound = (Settlement) objectManager.ReadObjectReferenceFromXml("bound", typeof (Settlement), node);
      if (!this.Bound.IsTown)
        return;
      this.Bound.Town.SetTradeBoundVillageInternal(this);
    }

    public bool IsProducing(ItemObject item)
    {
      foreach ((ItemObject, float) production in (List<(ItemObject, float)>) this.VillageType.Productions)
      {
        if (production.Item1 == item)
          return true;
      }
      return false;
    }

    public float HearthChange
    {
      get
      {
        return Campaign.Current.Models.SettlementProsperityModel.CalculateHearthChange(this).ResultNumber;
      }
    }

    public float Militia => this.Owner.Settlement.Militia;

    public float MilitiaChange
    {
      get
      {
        return Campaign.Current.Models.SettlementMilitiaModel.CalculateMilitiaChange(this.Owner.Settlement).ResultNumber;
      }
    }

    public ExplainedNumber MilitiaChangeExplanation
    {
      get
      {
        return Campaign.Current.Models.SettlementMilitiaModel.CalculateMilitiaChange(this.Owner.Settlement, true);
      }
    }

    public ExplainedNumber HearthChangeExplanation
    {
      get => Campaign.Current.Models.SettlementProsperityModel.CalculateHearthChange(this, true);
    }

    public int GetHearthLevel()
    {
      if ((double) this.Hearth >= 600.0)
        return 2;
      return (double) this.Hearth >= 200.0 ? 1 : 0;
    }

    public override SettlementComponent.ProsperityLevel GetProsperityLevel()
    {
      if (this.GetHearthLevel() >= 2)
        return SettlementComponent.ProsperityLevel.High;
      return this.GetHearthLevel() >= 1 ? SettlementComponent.ProsperityLevel.Mid : SettlementComponent.ProsperityLevel.Low;
    }

    protected override void OnInventoryUpdated(ItemRosterElement item, int count)
    {
    }

    public enum VillageStates
    {
      Normal,
      BeingRaided,
      ForcedForVolunteers,
      ForcedForSupplies,
      Looted,
    }
  }
}
